/**
 * Gcc vector benchmark
 * Julien Etienne, 2008
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef VECTOR_H
#define VECTOR_H

/**
 * gcc 4.1.2 does not support C++ template in attributes
 * therefore we use defines ;)
 */

#ifndef VECTOR_TYPE
	#error VECTOR_TYPE must be defined.
#endif

#ifndef VECTOR_SIZE
	#error VECTOR_SIZE must be defined.
#endif

#ifndef USE_GCC_VECTOR
	#define USE_GCC_VECTOR 0
#endif

class Vector{
	typedef VECTOR_TYPE vector_gcc_internal
		__attribute__ (( vector_size (VECTOR_SIZE*sizeof(VECTOR_TYPE)) ));
	union vector_internal {
		vector_gcc_internal	gcc_internal;
		VECTOR_TYPE			values[VECTOR_SIZE];
	} elements;

	Vector(const vector_gcc_internal &vector_gcc_internal){
		this->elements.gcc_internal = vector_gcc_internal;
	}

public:
	Vector(){
	}

	Vector operator+(const Vector &v) const{
	#if USE_GCC_VECTOR != 0
		return Vector(
			this->elements.gcc_internal
			+ v.elements.gcc_internal
			);
	#else
		Vector result = *this;
		for(int i=0; i<VECTOR_SIZE; i++){
			result.elements.values[i] += v[i];
		}
		return result;
	#endif
	}

	Vector operator-(const Vector &v) const{
	#if USE_GCC_VECTOR != 0
		return Vector(
			this->elements.gcc_internal
			- v.elements.gcc_internal
			);
	#else
		Vector result = *this;
		for(int i=0; i<VECTOR_SIZE; i++){
			result.elements.values[i] -= v[i];
		}
		return result;
	#endif
	}

	Vector operator*(const Vector &v) const{
	#if USE_GCC_VECTOR != 0
		return Vector(
			this->elements.gcc_internal
			* v.elements.gcc_internal
			);
	#else
		Vector result = *this;
		for(int i=0; i<VECTOR_SIZE; i++){
			result.elements.values[i] *= v[i];
		}
		return result;
	#endif
	}

	Vector operator/(const Vector &v) const{
	#if USE_GCC_VECTOR != 0
		return Vector(
			this->elements.gcc_internal
			/ v.elements.gcc_internal
			);
	#else
		Vector result = *this;
		for(int i=0; i<VECTOR_SIZE; i++){
			result.elements.values[i] /= v[i];
		}
		return result;
	#endif
	}

	VECTOR_TYPE& operator[](int index){
		return elements.values[index];
	}

	const VECTOR_TYPE& operator[](int index) const{
		return elements.values[index];
	}
};

std::ostream& operator<<(std::ostream& os, const Vector& v){
	os << "[ ";
	for(int i=0; i<VECTOR_SIZE; i++){
		os << v[i] << " ";
	}
	os << "]";

	return os;
}

#endif

